package com.component.api;

import cn.hutool.core.clone.CloneSupport;
import com.alibaba.fastjson.JSON;
import com.component.api.excepiton.ComponentException;
import com.component.api.model.PortData;
import com.component.api.model.ProcessResult;
import com.component.api.model.dto.ColumnDTO;
import com.component.api.model.param.ParamPair;
import com.component.api.model.param.TableColumn;

import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 描述：
 * 抽象公共组件
 * @author xianggj
 * @Date 2021/10/12 16:22
 **/
public abstract class AbstractComponent extends CloneSupport<AbstractComponent> implements Serializable {

    private static final long serialVersionUID = -1L;

    /**
     * 流程唯一id
     */
    protected String flowKey;

    /**
     * 节点唯一id
     */
    protected String nodeId;

    public String getFlowKey() {
        return flowKey;
    }

    public void setFlowKey(String flowKey) {
        this.flowKey = flowKey;
    }

    public String getNodeId() {
        return nodeId;
    }

    public void setNodeId(String nodeId) {
        this.nodeId = nodeId;
    }

    /**
     * 这个为true 表示这个节点需要执行action动作
     */
    protected Boolean isNeedExec;

    public Boolean getNeedExec() {
        return isNeedExec == null? false : isNeedExec;
    }

    public void setNeedExec(Boolean needExec) {
        isNeedExec = needExec;
    }

    /**
     * 子类扫描路径
     *  所以子类 必须在这个包名下面
     */
    public static final String SUB_PATH = "com.etl.component";

    /**
     * 组件处理方法
     *
     * @param datas      输入数据
     * @param paramPairs 参数键值对
     * @return ProcessResult 结果和PortData一样 但是不允许一个输出端输出多个值
     */
    public abstract ProcessResult process(List<PortData> datas, List<ParamPair> paramPairs);

    /**
     * 预览输出端口字段
     *  递归传递
     *
     * @param datas      输入端口数据
     * @param paramPairs 参数键值对
     * @return
     */
    public abstract List<PortData> previewOutputColumns(List<PortData> datas, List<ParamPair> paramPairs);


    /**
     * 规则
     * @return
     */
    public abstract String getRule();

    /**
     * 参数转map
     * @param paramPairs
     * @return
     */
    public Map<String, ParamPair> paramToMap(List<ParamPair> paramPairs){
        Map<String, ParamPair> map = new HashMap<>();
        if (paramPairs == null){
            return map;
        }
        for (ParamPair paramPair : paramPairs) {
            map.put(paramPair.getName(), paramPair);
        }
        return map;
    }

    /**
     * 参数转对应值
     *  参数该是啥值由编写人员自行转换
     * @param paramPairs
     * @return
     */
    public Map<String, Object> paramToObject(List<ParamPair> paramPairs){
        Map<String, Object> map = new HashMap<>();
        if (paramPairs == null){
            return map;
        }
        for (ParamPair paramPair : paramPairs) {
            String value = paramPair.getValue();
            switch (paramPair.getType()) {
                case INT:
                    map.put(paramPair.getName(), Integer.valueOf(value));
                    break;
                case DOUBLE:
                    map.put(paramPair.getName(), Double.valueOf(value));
                    break;
                case BOOLEAN:
                    map.put(paramPair.getName(), Boolean.valueOf(value));
                    break;
                case OBJECT:
                    map.put(paramPair.getName(), JSON.parseObject(value, paramPair.getValueType()));
                    break;
                case ARRAY:
                    map.put(paramPair.getName(), JSON.parseArray(value, paramPair.getValueType()));
                    break;
                default:
                    map.put(paramPair.getName(), value);
            }
        }
        return map;
    }

    /**
     * 获取int类型的数
     * @param numStr
     * @return
     */
    protected Integer getInteger(Object numStr) {
        return (numStr == null || numStr.toString().length() == 0)?0:
                Integer.valueOf(numStr.toString().replace("\"", ""));
    }

    /**
     * 查找某列坐标
     * @param colName
     */
    protected int indexOfIgnoreCase(List<String> colName, String col) {
        for (int i = 0; i < colName.size() ; i++) {
            String s = colName.get(i);
            if (s.equalsIgnoreCase(col)){
                return i;
            }
        }
        throw new RuntimeException("不存在列： " + col);
    }


    /**
     * 获取序号并设置序号
     * @param columnDTOS
     * @param columns
     */
    protected void setIndex(List<? extends ColumnDTO> columnDTOS, List<TableColumn> columns) {
        List<String> colnames = columns.stream().map(e -> e.getColumnName()).collect(Collectors.toList());
        for (ColumnDTO columnDTO : columnDTOS) {
            int i = colnames.indexOf(columnDTO.getField());
            if (i == -1){
                throw new ComponentException("数据来源列和输出列不对应，数据来源列中缺少列" + columnDTO.getField());
            }
            columnDTO.setIndex(i);
        }
    }

}
